package com.hengxing.demo.Service;

import org.springframework.stereotype.Service;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author hengxing
 * @version 1.0
 * @project SocketDemoHx
 * @date 5/30/2023 15:11:18
 */
@Service
public class TagService {
    private Socket socket = null;
    DataOutputStream bw;//输出流
    DataInputStream br;//输入流
    private boolean bConnected = false;


    /**
     * 返回连接状态
     * @Return boolean - true if connected
     * @Author hengxing
     * @Date 6/1/2023 10:44:03
     */
    public boolean isConnected(){
        return bConnected;
    }

    // 连接
    public void connect(String addr) {
        try {
            socket = new Socket(InetAddress.getByName(addr.trim()), 4660); // Server IP and Port
            bw = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
            br = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
            bConnected = true;
            System.out.println(" Connect to server  OK !");

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    // 断开连接
    public void disconnect() {
        System.out.println("Close");
        try {
            if (bw != null) {
                bw.close();
                bw = null;
            }
            if (socket != null) {
                if (!socket.isClosed()) {
                    socket.shutdownInput();
                }
                if (!socket.isClosed()) {
                    socket.shutdownOutput();
                }
                if (!socket.isClosed()) {
                    socket.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    byte[] ns = new byte[256];
    char[] tmpChar = new char[1];
    int i, len, idx;

    StringBuffer s = new StringBuffer();
    String msg, tmpStr;


    //end clas
    //接收线程
    class ThreadRecv implements Callable<String> {

        byte[] in_buf = new byte[15];
        int len_recv;

        String resp, hs, stmp, hexresp;

        public String call() {
            String return_str = "";
            try {
                while (bConnected) {
                    len_recv = br.read(in_buf, 0, 15);
                    resp = new String(in_buf, 0, in_buf.length);

                    //----------- Convert Command ------------//
                    hs = "";
                    stmp = "";

                    for (int n = 0; n < in_buf.length; n++) {
                        stmp = (java.lang.Integer.toHexString(in_buf[n] & 0XFF));
                        if (stmp.length() == 1) {
                            hs = hs + " " + "0" + stmp;
                        } else {
                            hs = hs + " " + stmp;
                        }
                    }
                    System.out.println(" Server to Client --> " + hs);
//                    taContent.setText(" Server to Client --> " + hs);
                    String SubCommand = (java.lang.Integer.toHexString(in_buf[6] & 0XFF));
                    String addr = (java.lang.Integer.toHexString(in_buf[7] & 0XFF));
                    System.out.println("本次获取数据结束：SubCommand：" + SubCommand + "，标签地址：" + addr);
                    if (in_buf.length > 7) {
                        for (int n = 8; n < in_buf.length; n++) {
                            char a = (char) ((int) in_buf[n]);
                            return_str = return_str + a;
                        }
                        System.out.println(" Server to Client --> " + return_str);
                    }
                }
            } catch (SocketException se) {
                System.out.println("Exit");
            } catch (IOException ioe) {
                ioe.printStackTrace();
            } finally {
                if (br != null) {
                    try {
                        br.close();
                        br = null;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                return return_str;
            }
        }//end public void run()

    }


    /**
     * 熄灭标签
     * @Param p_addr
     * @Return void
     * @Author hengxing
     * @Date 6/1/2023 13:57:22
     */
    public void TagClear(byte p_addr) {
        try {
            byte[] bytes = new byte[8];
            bytes[0] = 8;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] = 1;
            bytes[7] = p_addr;
            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }

    // 模拟按键
    public void monittag(byte p_addr) {
        try {
            byte[] bytes = new byte[8];
            bytes[0] = 8;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] =23;
            bytes[7] = p_addr;
            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }

    // 是否启用感应标签
    public void AB_SNR_Control(byte p_addr, byte p_able, byte p_epr) {
        try {
            byte[] bytes = new byte[11];;
            if (p_epr == 0) {
                bytes = new byte[11];
                bytes[0] = 11;//数据长度
                bytes[1] = 0;
                bytes[2] = 96;
                bytes[6] = 31;
                bytes[7] = p_addr;
                bytes[8] = 18;
                bytes[9] = 0;
                bytes[10] = p_able;
            } else {
                bytes = new byte[12];
                bytes[0] = 12;//数据长度
                bytes[1] = 0;
                bytes[2] = 96;
                bytes[6] = 31;
                bytes[7] = p_addr;
                bytes[8] = 18;
                bytes[9] = 0;
                bytes[10] = p_able;
                bytes[11] = 85;
            }

            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }

    // 是否启用感应标签  1 启用 ，0不启用
    public void AB_SNR_SetRange(byte p_addr, byte p_range, byte p_epr) {
        try {
            byte[] bytes = new byte[11];;
            if (p_epr == 0) {
                bytes = new byte[11];
                bytes[0] = 11;//数据长度
                bytes[1] = 0;
                bytes[2] = 96;
                bytes[6] = 31;
                bytes[7] = p_addr;
                bytes[8] = 18;
                bytes[9] = 2;
                bytes[10] = p_range;
            } else {
                bytes = new byte[12];
                bytes[0] = 12;//数据长度
                bytes[1] = 0;
                bytes[2] = 96;
                bytes[6] = 31;
                bytes[7] = p_addr;
                bytes[8] = 18;
                bytes[9] = 2;
                bytes[10] = p_range;
                bytes[11] = 85;
            }

            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }

    // 设置感应灵敏度 0-5
    public void AB_SNR_DetectTime(byte p_addr, byte p_detect, byte p_epr) {
        try {
            byte[] bytes = new byte[11];;
            if (p_epr == 0) {
                bytes = new byte[11];
                bytes[0] = 11;//数据长度
                bytes[1] = 0;
                bytes[2] = 96;
                bytes[6] = 31;
                bytes[7] = p_addr;
                bytes[8] = 18;
                bytes[9] = 3;
                bytes[10] = p_detect;
            } else {
                bytes = new byte[12];
                bytes[0] = 12;//数据长度
                bytes[1] = 0;
                bytes[2] = 96;
                bytes[6] = 31;
                bytes[7] = p_addr;
                bytes[8] = 18;
                bytes[9] = 3;
                bytes[10] = p_detect;
                bytes[11] = 85;
            }

            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }

    /**
     * 显示数字
     * @Param p_addr
	 * @Param p_str
     * @Return void
     * @Author hengxing
     * @Date 6/1/2023 15:45:48
     */
    public void displayNumber(byte p_addr, String p_str) {
        try {
            char[] chars = new char[6];
            String[] split = p_str.split("\\.");
            String numberWithoutDot = String.join("",split);

            if (numberWithoutDot.length() < 6) {
                int p_length = numberWithoutDot.length();
                for (int i = 0; i < (6 - p_length); i++) {
                    numberWithoutDot = " " + numberWithoutDot;
                }
            }
            if (numberWithoutDot.length() > 6) {
                numberWithoutDot = numberWithoutDot.substring(0, 6);
            }
            System.out.println(p_str);
            System.out.println("numberWithoutDot = " + numberWithoutDot);
            char[] strChar = numberWithoutDot.toCharArray();//先显示数字

            byte[] bytes = new byte[15];
            bytes[0] = 15;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] = 0;
            bytes[7] = p_addr;

            for (int i = 0; i < 6; i++) {
                bytes[8 + i] = (byte) strChar[i];
            }

            //再显示小数位
            bytes[14] = getDotIndex(p_str);//小数位 16进制位上，为1的就点亮。

            bw.write(bytes);
            bw.flush();
        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }

    // 设置完成后显示 1 显示 0 不显示
    public void AB_SNR_ResidualDSP(byte p_addr, byte p_dsp) {
        try {
            byte[] bytes = new byte[10];;


            bytes[0] = 10;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] = 31;
            bytes[7] = p_addr;
            bytes[8] = 10;
            bytes[9] = p_dsp;



            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }
    // 自动报警 1 自动报警 0 关闭
    public void AB_SNR_AutoWarn(byte p_addr, byte p_warn) {

        try {
            byte[] bytes = new byte[10];;

            bytes[0] = 10;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] = 31;
            bytes[7] = p_addr;
            bytes[8] = 3;
            bytes[9] = 1;

            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
        try {
            byte[] bytes = new byte[10];;

            bytes[0] = 10;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] = 31;
            bytes[7] = p_addr;
            bytes[8] = 10;
            if (p_warn == 1) {
                bytes[9] = 5;
            } else {
                bytes[9] = 6;
            }

            bw.write(bytes);
            bw.flush();

        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }


    /**
     * 设置灯的闪烁频率
     * @Param p_addr 标签地址
	 * @Param p_status  0 灭，1 常亮，2 2秒，3 1秒，4 0.5秒，5 0.25秒
     * @Return void
     * @Author hengxing
     * @Date 6/1/2023 10:47:17
     */
    public  void AB_LED_Status(byte p_addr,byte p_status) {
        try {
            byte[] bytes = new byte[10];
            bytes[0] = 10;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] = 31;
            bytes[7] = p_addr;

            //设置灯的状态
            bytes[8] = 4;
            bytes[9] = p_status;
            bw.write(bytes);
            bw.flush();
        } catch (IOException e) {
            bConnected=false;
            e.printStackTrace();
        }
    }

    /**
     * 设置灯的颜色
     * @Param p_addr 标签地址
	 * @Param p_color 0 红 1 绿 2 黄 3 蓝 4 紫 5 浅蓝
     * @Return void
     * @Author hengxing
     * @Date 6/1/2023 10:48:13
     */
    public  void AB_LED_color(byte p_addr,byte p_color)
    {
        try {
            byte[] bytes = new byte[10];
            bytes[0] = 10;//数据长度
            bytes[1] = 0;
            bytes[2] = 96;
            bytes[6] = 31;
            bytes[7] = p_addr;
            bytes[8] = 0;
            bytes[9] = p_color;
            bw.write(bytes);

            bw.flush();
        } catch (IOException e) {
            bConnected=false;
            e.printStackTrace();
        }
    }

    /**
     * 返回按钮信息
     * @Return java.lang.String
     * @Author hengxing
     * @Date 5/30/2023 16:55:45
     */
    public String returnData() throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                byte[] in_buf = new byte[15];
                int len_recv;

                String resp, hs, stmp, hexresp;

                String return_str = "";
                try {
                    while (bConnected) {
                        len_recv = br.read(in_buf, 0, 15);
                        resp = new String(in_buf, 0, in_buf.length);

                        //----------- Convert Command ------------//
                        hs = "";
                        stmp = "";

                        for (int n = 0; n < in_buf.length; n++) {
                            stmp = (java.lang.Integer.toHexString(in_buf[n] & 0XFF));
                            if (stmp.length() == 1) {
                                hs = hs + " " + "0" + stmp;
                            } else {
                                hs = hs + " " + stmp;
                            }
                        }

                        System.out.println(" Server to Client --> " + hs);
                        String SubCommand = (java.lang.Integer.toHexString(in_buf[6] & 0XFF));
                        String addr = (java.lang.Integer.toHexString(in_buf[7] & 0XFF));
                        System.out.println("本次获取数据结束：SubCommand：" + SubCommand + "，标签地址：" + addr);
                        if (in_buf.length > 7) {
                            for (int n = 8; n < in_buf.length; n++) {
                                char a = (char) ((int) in_buf[n]);
                                return_str = return_str + a;
                            }
                            System.out.println(" Server to Client --> " + return_str);

                        }
                        //hexresp = Integer.toHexString(len_recv); //ByteLength to HexString
                        //System.out.println("hexString =" + hexresp);
                    }
                } catch (SocketException se) {
                    System.out.println("Exit");
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                } finally {
                    if (br != null) {
                        try {
                            br.close();
                            br = null;
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    return return_str;
                }//end public void run()
            }
        });
        new Thread(task).start();
        String s = task.get();
        return s;
    }

    /**
     * 设置默认模板信息
     * @Param address 标签地址
	 * @Param offset 1-4 有四个出厂预置模板
     * @Return void
     * @Author hengxing
     * @Date 5/31/2023 15:09:03
     */
    public void setDefaultPageLcd(int address, int offset){
//        try {

            byte[] data = new byte[2];
            data[0] = (byte) Integer.parseInt("A0",16);
            data[1] = (byte) (Integer.parseInt("00",16) + offset - 1);//模板编号
            sendToLcd(address,"27",data);

            /* 旧的写法
            byte[] bytes = new byte[10];
            bytes[0] = 10;//数据长度
            bytes[1] = 0;
            bytes[2] = (byte) Integer.parseInt("60",16);
            bytes[6] = (byte) Integer.parseInt("27",16);
            bytes[7] = (byte) address;
            bytes[8] = (byte) Integer.parseInt("A0",16);
            bytes[9] = (byte) (Integer.parseInt("00",16) + offset - 1);//模板编号

            System.out.println("bytes = " + Arrays.toString(bytes));
            bw.write(bytes);
            bw.flush();
        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }*/
    }

    /**
     * 设置行元素格式 TODO
     * @Param address 标签地址
	 * @Param data 格式数据
     * @Return void
     * @Author hengxing
     * @Date 5/31/2023 16:00:09
     */
    public void setRowElement(int address,byte[] data){
        sendToLcd(address,"27",data);
    }

//    public void sendString(int address,String message){
//        new byte[]
//
//    }


    /**
     * 私有方法，用来传输数据
     * @Param address 标签地址
	 * @Param command 命令-十六进制
	 * @Param data 数据
     * @Return void
     * @Author hengxing
     * @Date 5/31/2023 15:34:57
     */
    private void sendToLcd(int address,String command,byte[] data){
        try {
            int pocketLength = 8 + data.length;//数据包长度
            byte[] bytes = new byte[pocketLength];
            bytes[0] = (byte) pocketLength;//数据长度
            bytes[1] = 0;
            bytes[2] = (byte) Integer.parseInt("60",16);
            bytes[6] = (byte) Integer.parseInt(command,16);
            bytes[7] = (byte) address;
            for (int j = 0; j < data.length; j++) {
              bytes[8 + j] = data[j];
            }

            System.out.println("bytes = " + Arrays.toString(bytes));
            bw.write(bytes);
            bw.flush();
        } catch (IOException e) {
            bConnected = false;
            e.printStackTrace();
        }
    }

    /**
     * 私有方法，获取点的位置，只允许有一个小数点
     * @Param number
     * @Return byte 一个byte的位中为1的位置点亮小数点，该数字的对应10进制数转为byte
     * @Author hengxing
     * @Date 6/1/2023 17:12:34
     */
    private byte getDotIndex(String number){
        byte dotIndex = 0;
        if (number.contains(".")){
            int length = number.split("\\.")[1].length();//切分出小数部分的长度
            //1.314
            dotIndex = (byte) (Math.pow(2,length));
        }
        return dotIndex;
    }
}
